 /* 
  *  Syntelos XB
  *  Copyright (C) 2006 John Pritchard.
  *
  *  This program is free software; you can redistribute it and/or
  *  modify it under the terms of the GNU General Public License as
  *  published by the Free Software Foundation; either version 2 of
  *  the License, or (at your option) any later version.
  *
  *  This program is distributed in the hope that it will be useful,
  *  but WITHOUT ANY WARRANTY; without even the implied warranty of
  *  MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the GNU
  *  General Public License for more details.
  *
  *  You should have received a copy of the GNU General Public License
  *  along with this program; if not, write to the Free Software
  *  Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA
  *  02111-1307 USA
  */

package syntelos.xb.op;

/**
 * <p> Child of {@link syntelos.xb.at.Code} containing virtual
 * machine code. </p>
 * 
 * @see syntelos.xb.at.Code
 */
public final class Code 
    extends syntelos.xb.Base
    implements syntelos.xb.XB.XOP
{
    public final static syntelos.iou.dom.Name NAME = new syntelos.iou.dom.impl.Name(ELEMENT_NODE,"http://www.syntelos.org/xb/op","xop:code");


    private syntelos.iou.bbuf iobuffer = new syntelos.iou.bbuf();
    
    public Code(org.w3c.dom.Document doc, syntelos.iou.dom.Name name){
	super(doc,name);
    }
    public Code(org.w3c.dom.Document doc){
	this(doc,NAME);
    }
    public Code(){
	this(DOC_NIL);
    }


    public syntelos.xb.at.Code getAttributeCode(){
	return (syntelos.xb.at.Code)this.getParentNode();
    }
    public syntelos.xb.at.LocalVariableTable getAttributeLocalVariableTable(){
	return this.getAttributeCode().getAttributeLocalVariableTable();
    }
    public syntelos.xb.at.LineNumberTable getAttributeLineNumberTable(){
	return this.getAttributeCode().getAttributeLineNumberTable();
    }
    public syntelos.xb.op.Code getOpCode(){
	return this;
    }
    public syntelos.xb.Method getMethod(){
	return this.getAttributeCode().getMethod();
    }
    public syntelos.xb.op.Exceptions getOpExceptions(){
	return this.getAttributeCode().getOpExceptions();
    }
    public syntelos.xb.Op getOp(syntelos.xb.IO.Uri uri){
	java.lang.String id = uri.getPath();
	if (null != id){
	    try {
		int pc = syntelos.xb.IO.Uri.Integer(id);
		return this.getOpByPC(pc);
	    }
	    catch (syntelos.xb.Error.Argument ear){
		/*
		 * Compatible with user defined, 'id' based
		 * labels for "op:<id>" references.
		 */
		return (syntelos.xb.Op)this.getChildById(id);
	    }
	}
	else
	    throw new syntelos.xb.Error.Argument(this,uri.toString());
    }
    public syntelos.xb.Op getOpByIndex(int idx){
	return (syntelos.xb.Op)this.getChildByIndex(idx);
    }
    public syntelos.xb.Op getOpByPC(int pc){
	if (this.hasChildNodes()){
	    org.w3c.dom.NodeList children = this.getChildNodes();
	    syntelos.xb.Op test;
	    int index = pc, test_pc;
	    while (true){
		test = (syntelos.xb.Op)children.item(index);
		if (null != test && pc == test.getPC())
		    return test;
		else {
		    index -= 1;
		    if (0 > index)
			return null;
		}
	    }
	}
	else
	    return null;
    }
    public int indexOp(syntelos.xb.Op instr){
	if (this.hasChildNodes()){
	    syntelos.iou.dom.NodeList children = this.getChildNodes2();
	    return children.item(instr);
	}
	else
	    return -1;
    }
    public int countOp(){
	return this.getChildNodes().getLength();
    }
    /**
     * Called by {@link syntelos.xb.Method#buildpost()} to produce
     * {@link syntelos.xb.Op} children from CF I/O buffer.
     */
    public syntelos.iou.dom.Node decompile(){
	this.iobuffer.reset_read();
	if (0 < this.iobuffer.available()){
	    syntelos.xb.Method method = this.getMethod();
	    syntelos.xb.Class xclass = method.getDeclaringClass();
	    syntelos.xb.Op op;
	    /*
	     * Produce op object set
	     */
	    try {
		syntelos.xb.Op.Reader reader = new syntelos.xb.Op.Reader.Buffer(this.iobuffer);
		int opc;
		while (-1 < (opc = reader.read())){
		    op = syntelos.xb.Op.New(opc);
		    this.appendChild(op);
		    op.readCF(xclass,method,reader);
		}
	    }
	    catch (java.io.IOException iox){
		syntelos.xb.Error err = new syntelos.xb.Error.Bug("unreachable");
		err.initCause(iox);
		throw err;
	    }
	}
	/*
	 * Decompile op set (pull or push constant operands, etc)
	 * 
	 * -document order traversal-
	 */
	return this;
    }
    public syntelos.iou.dom.Node compile(){
	this.iobuffer.resetall();
	syntelos.xb.Method method = this.getMethod();
	syntelos.xb.Class xclass = method.getDeclaringClass();
	/*
	 * Write method code to buffer 
	 */
	syntelos.xb.Op.Writer writer = new syntelos.xb.Op.Writer.Buffer(this.iobuffer);
	try {
	    syntelos.xb.Op op;
	    for (int idx = 0, len = this.countOp(); idx < len; idx++){
		op = this.getOpByIndex(idx);
		op.writeCF(xclass,method,writer);
	    }
	}
	catch (java.io.IOException iox){
	    syntelos.xb.Error err = new syntelos.xb.Error.Bug("unreachable");
	    err.initCause(iox);
	    throw err;
	}
	return this;
    }
    public int atlen(){
	/*
	 * return buffer length
	 */
	return (4 + this.iobuffer.length());
    }
    public void readCF(syntelos.xb.IO.Uri src, syntelos.xb.CF.Reader reader)
	throws java.io.IOException
    {
	/*
	 * Read code length
	 */
	int code_len = reader.readInt();
	byte[] copy = new byte[code_len];
	/*
	 * Read method code
	 */
	reader.readFully(copy,0,code_len);
	/*
	 * Clean method code buffer
	 */
	this.iobuffer.resetall();
	/*
	 * Buffer method code 
	 */
	this.iobuffer.write(copy,0,code_len);
	copy = null;//(gc lvar)
    }
    public void writeCF(syntelos.xb.IO.Uri dst, syntelos.xb.CF.Writer writer)
	throws java.io.IOException
    {
	int code_len = this.iobuffer.length();
	/*
	 * Write code length
	 */
	writer.writeInt(code_len);
	byte[] copy = this.iobuffer.toByteArray();
	/*
	 * Write code body
	 */
	writer.write(copy,0,code_len);
	copy = null;//(gc lvar)
    }
}
